using System;
using System.Xml;
using DesignByContract;
using Outcoding.GraphGenerator.Entities;
using Outcoding.GraphGenerator.Util.Logging;

namespace Outcoding.GraphGenerator.Composition{
    public class LegendBuilder : BuilderBase{
        #region Attributes

        private string fontColorAttr = "font-color";
        private string fontDecorationAttr = "font-decoration";
        private string fontNameAttr = "font-name";
        private string fontSizeAttr = "font-size";
        private string positionAttr = "position";
        private string visibleAttr = "visible";

        #endregion

        private readonly string mNodeName = XmlTagNames.legend.ToString();

        private XmlNode mNode;

        private string mNodePath{
            get { return "./" + mNodeName; }
        }

        public override void SelectNode(XmlDocument document){
            throw new Exception("The method or operation is not implemented.");
        }

        public override void Compose(){
            throw new Exception("The method or operation is not implemented.");
        }

        public override void Compose(XmlNode node){
            mNode = node.SelectSingleNode(mNodePath);
            try{
                BuildObject(mNode);
            }
            catch (PreconditionException preExc){
                LogManager.Instance.LogWarning("Legend entity could not be created; process aborted.", preExc);
            }
        }

        public override void AppendToParent(object parent){
            Check.Require(parent is Graph, "Parent object not a valid argument");
            (parent as Graph).Legend = (Legend) mProduct;
        }

        private void BuildObject(XmlNode legendXmlNode){
            var legend = new Legend();
            try{
                if (legendXmlNode.Attributes[positionAttr] != null)
                    legend.Position = ParsePositionAttribute(legendXmlNode);
                if (legendXmlNode.Attributes[visibleAttr] != null)
                    legend.IsVisible = ParseIsVisibleAttribute(legendXmlNode);
                //font attributes
                if (legendXmlNode.Attributes[fontNameAttr] != null)
                    legend.FontName = ParseFontNameAttribute(legendXmlNode);
                if (legendXmlNode.Attributes[fontSizeAttr] != null)
                    legend.FontSize = ParseFontSizeAttribute(legendXmlNode);
                if (legendXmlNode.Attributes[fontDecorationAttr] != null){
                    legend.IsFontBold = ParseIsFontBoldAttribute(legendXmlNode);
                    legend.IsFontItalic = ParseIsFontItalicAttribute(legendXmlNode);
                    legend.IsFontUnderline = ParseIsFontUnderlineAttribute(legendXmlNode);
                }
                if (legendXmlNode.Attributes[fontColorAttr] != null)
                    legend.Color = ParseColorAttribute(legendXmlNode);
            }
            catch (PreconditionException preExc){
                //log error
                legend = null;
                throw;
            }

            mProduct = legend;
        }

        private bool ParseIsVisibleAttribute(XmlNode legendXmlNode){
            Check.Require(legendXmlNode.Attributes[visibleAttr] != null, "visible attribute not present");
            return Boolean.Parse(legendXmlNode.Attributes[visibleAttr].Value);
        }

        private LegendPosition ParsePositionAttribute(XmlNode legendXmlNode){
            Check.Require(legendXmlNode.Attributes[positionAttr] != null, "position attribute not present");
            return ConvertPositionFromName(legendXmlNode.Attributes[positionAttr].Value.Trim());
        }

        private string ParseFontNameAttribute(XmlNode legendXmlNode){
            Check.Require(legendXmlNode.Attributes[fontNameAttr] != null, "font-name attribute not present");
            return legendXmlNode.Attributes[fontNameAttr].Value;
        }

        private int ParseFontSizeAttribute(XmlNode legendXmlNode){
            Check.Require(legendXmlNode.Attributes[fontSizeAttr] != null, "font-size attribute not present");
            return Int32.Parse(legendXmlNode.Attributes[fontSizeAttr].Value);
        }

        private bool ParseIsFontBoldAttribute(XmlNode legendXmlNode){
            Check.Require(legendXmlNode.Attributes[fontDecorationAttr] != null, "font-decoration attribute not present");
            return legendXmlNode.Attributes[fontDecorationAttr].Value.Contains("bold");
        }

        private bool ParseIsFontItalicAttribute(XmlNode legendXmlNode){
            Check.Require(legendXmlNode.Attributes[fontDecorationAttr] != null, "font-decoration attribute not present");
            return legendXmlNode.Attributes[fontDecorationAttr].Value.Contains("italic");
        }

        private bool ParseIsFontUnderlineAttribute(XmlNode legendXmlNode){
            Check.Require(legendXmlNode.Attributes[fontDecorationAttr] != null, "font-decoration attribute not present");
            return legendXmlNode.Attributes[fontDecorationAttr].Value.Contains("underline");
        }

        private long ParseColorAttribute(XmlNode legendXmlNode){
            Check.Require(legendXmlNode.Attributes[fontColorAttr] != null, "color attribute not present");

            return Entities.Util.ColorTranslation(legendXmlNode.Attributes[fontColorAttr].Value);
        }

        private LegendPosition ConvertPositionFromName(string positionName){
            Check.Require(positionName != null, "Position name not defined");

            LegendPosition legendPosition = LegendPosition.xlLegendPositionUnknown;
            switch (positionName){
                case "xlLegendPositionBottom":
                    legendPosition = LegendPosition.xlLegendPositionBottom;
                    break;
                case "xlLegendPositionLeft":
                    legendPosition = LegendPosition.xlLegendPositionLeft;
                    break;
                case "xlLegendPositionRight":
                    legendPosition = LegendPosition.xlLegendPositionRight;
                    break;
                case "xlLegendPositionTop":
                    legendPosition = LegendPosition.xlLegendPositionTop;
                    break;
                case "xlLegendPositionCorner":
                    legendPosition = LegendPosition.xlLegendPositionCorner;
                    break;
                default:
                    break;
            }
            return legendPosition;
        }
    }
}